#include "pSystem.h"
#include "scene.h"

pSystem::pSystem(void)
{
	//created = getTime();
	LARGE_INTEGER now;
	QueryPerformanceCounter(&now);
	created = now.LowPart;
}

pSystem::~pSystem(void)
{

}

void pSystem::recalc()
{
	if (!this->alive) return;
	unsigned long now = getTime();
	unsigned long elapsed;
	
	for(int i = 0; i < data.size(); i++)
	{
		elapsed = now - data[i]->birth;
		if (elapsed < data[i]->ttl)
			data[i]->posicion = data[i]->origen + data[i]->velocidad * elapsed;
	}

	std::vector<int> eliminar;
	//marcamos las particulas que mueren para eliminarlas
	for(int i = 0; i < data.size(); i++)
	{
		elapsed = now - data[i]->birth;
		if( elapsed >= data[i]->ttl)
			eliminar.push_back(i);
	}
	//eliminamos las particulas
	for(int i = eliminar.size()-1; i >= 0 ; i--)
	{
		data.erase(data.begin() + eliminar[i]);
	}
	//create(this->origen, eliminar.size());
	if(data.size()==0) alive = false;
}
/*
void pSystem::render()
{
	
	//Hay que hacer bill boarding
	glPushAttrib(GL_COLOR_BUFFER_BIT);
	//glDisable(GL_DEPTH_TEST);
	glEnable(GL_BLEND);
	glBlendFunc(GL_SRC_ALPHA, GL_ONE);
	glEnable(GL_TEXTURE_2D);
	
	Scene::getScene()->ActivateTexture("gauss");
	
	glColor4f(1.0,0.2,0.3,0.6);
	glBegin(GL_QUADS);
	for (int i = 0; i < data.size(); i++)
	{
		data[i]->render();
	}
	glEnd();
	
	glDisable(GL_TEXTURE_2D);
	glDisable(GL_BLEND);
	glEnable(GL_DEPTH_TEST);
	glPopAttrib();
	
}

*/

void pSystem::setFollowing(Instance* _instance, Vector3 _offset){
	following = _instance;
	_offset = _offset;
}

//====================================================
//   explosion
//====================================================

void explossionPS::recalc()
{
	if (!this->alive) return;
	unsigned long now = getTime();
	unsigned long elapsed;
	float ratio;
	for(int i = 0; i < data.size(); i++)
	{
		elapsed = now - data[i]->birth;
		if (elapsed == 0){
			elapsed ++;
		}
		ratio = 1.0 - ((float)elapsed/(float)data[i]->ttl);
		if (elapsed < data[i]->ttl)
			data[i]->posicion = data[i]->origen + data[i]->velocidad * elapsed;
			
			data[i]->size *= ratio;
	}

	std::vector<int> eliminar;
	//marcamos las particulas que mueren para eliminarlas
	for(int i = 0; i < data.size(); i++)
	{
		elapsed = now - data[i]->birth;
		if( elapsed >= data[i]->ttl)
			eliminar.push_back(i);
	}

	//eliminamos las particulas
	for(int i = eliminar.size()-1; i >= 0 ; i--)
	{
		data.erase(data.begin() + eliminar[i]);
	}
	
	if(data.size() == 0) alive = false;
}
void explossionPS::render()
{
	if (!this->alive) return;
	//Hay que hacer bill boarding
	glPushAttrib(GL_ALL_ATTRIB_BITS);
	glDepthMask(false);
	glEnable(GL_BLEND);
	glBlendFunc(GL_SRC_ALPHA, GL_ONE);
	glEnable(GL_TEXTURE_2D);
	
	Scene::getScene()->ActivateTexture("explossion");
	
	glColor4f(1.0,0.5,0.0,0.9);
	glBegin(GL_QUADS);
	for (int i = 0; i < data.size(); i++)
	{
		data[i]->render();
	}
	glEnd();

	glPopAttrib();
}


void explossionPS::create(Vector3 _origen, int _number)
{
	this->alive = true;
	this->origen = _origen;
	Vector3 origen, velocidad;
	unsigned int birth,ttl;
	float x,y,z,rango,mod_vel,uni,randm;
	rango = 1.0f;
	srand((unsigned)getTime());
	data.resize(_number);
	for (int i = 0; i < _number; i++ )
	{
		randm = rand();
		x = ((randm / RAND_MAX)-0.5) * rango / 300.0;
		randm = rand();
		y = ((randm / RAND_MAX)-0.5) * rango / 300.0;
		randm = rand();
		z = ((randm / RAND_MAX)-0.5) * rango / 300.0;
		origen = _origen + Vector3(x,y,z);

		randm = rand();
		mod_vel = (randm /RAND_MAX)*( rango/500.0);// * 10.0;
		randm = rand();
		x = ((randm / RAND_MAX)-0.5) * rango/100.0 ;
		randm = rand();
		y = ((randm / RAND_MAX)-0.5) * rango/100.0 ;
		randm = rand();
		z = ((randm / RAND_MAX)-0.5) * rango/100.0 ;

		velocidad = Vector3(x,y,z);
		velocidad.normalize();
		velocidad = velocidad*0.01;

		birth = getTime();
		randm = rand();
		x = ((randm / RAND_MAX)-0.5) * 100.0 ;
		ttl = 500.0 + x;
		data[i] = (new Particle(origen, velocidad, birth,ttl, Vector2(2,1)));
	}

}

//====================================================

void shipExplossionPS::create(Vector3 _origen, int _number)
{
	this->alive = true;
	this->origen = _origen;
	Vector3 origen, velocidad;
	unsigned int birth,ttl;
	float x,y,z,rango,mod_vel,uni,randm;
	rango = 1.0f;
	srand((unsigned)getTime());
	data.resize(_number);
	for (int i = 0; i < _number; i++ )
	{
		randm = rand();
		x = ((randm / RAND_MAX)-0.5) * rango / 300.0;
		randm = rand();
		y = ((randm / RAND_MAX)-0.5) * rango / 300.0;
		randm = rand();
		z = ((randm / RAND_MAX)-0.5) * rango / 300.0;
		origen = _origen + Vector3(x,y,z);

		randm = rand();
		mod_vel = (randm /RAND_MAX)*( rango/1.0) * 10.0;// * 10.0;
		randm = rand();
		x = ((randm / RAND_MAX)-0.5) * rango/80.0 ;
		randm = rand();
		y = ((randm / RAND_MAX)-0.5) * rango/80.0 ;
		randm = rand();
		z = ((randm / RAND_MAX)-0.5) * rango/80.0 ;

		velocidad = Vector3(x,y,z);
		velocidad.normalize();
		velocidad = velocidad*0.5;

		birth = getTime();
		randm = rand();
		x = ((randm / RAND_MAX)-0.5) * 500.0 ;
		ttl = 3000.0 + x;
		data[i] = (new Particle(origen, velocidad, birth,ttl, Vector2(15,1)));
	}

}

//====================================================
void ringExplossionPS::create(Vector3 _origen, int _number)
{
	this->alive = true;
	this->origen = _origen;
	Vector3 origen, velocidad;
	unsigned int birth,ttl;
	float x,y,z,rango,mod_vel,uni,randm,rndmax, xx,yy,zz ;

	rango = 1.0f;
	srand((unsigned)getTime());
	data.resize(_number);
	randm = rand();
	mod_vel = ((randm / RAND_MAX) - 0.01) * (rango) * 1.0;
	randm = rand();
	randm /= RAND_MAX;
	if(randm < 0.33){
		xx = 200.0;
		yy = 10.0;
		zz = 10.0;
	}
	else if(randm < 0.66){
		xx = 10.0;
		yy = 200.0;
		zz = 10.0;
	}
	else{
		xx = 10.0;
		yy = 10.0;
		zz = 200.0;
	} 
	for (int i = 0; i < _number; i++ )
	{
		
		randm = rand();
		x = (((randm) / RAND_MAX)-0.5) * (rango/xx);
		randm = rand();
		y = (((randm) / RAND_MAX)-0.5) * (rango/yy);
		randm = rand();
		z = (((randm) / RAND_MAX)-0.5) * (rango/zz);
		
		origen = _origen + Vector3(x+0.1,y,z+0.1);
		randm = rand();
		x = ((randm / RAND_MAX)-0.5) * (rango/xx) ;
		randm = rand();
		y = ((randm / RAND_MAX)-0.5) * (rango/yy) ;
		randm = rand();
		z = ((randm / RAND_MAX)-0.5) * (rango/zz) ;

		velocidad = Vector3(x,y,z);
		velocidad.normalize();
		velocidad = velocidad * mod_vel;

		birth = getTime();
		randm = rand();
		x = ((randm / RAND_MAX)-0.5) * 500.0 ;
		ttl = 5000.0 + x;
		data[i] = (new Particle(origen, velocidad, birth,ttl, Vector2(7,1)));
	}

}


void enginePS::create(int _number, Instance * _following, Vector3 _offset,double _size)
{
	this->following = _following;
	Ship* ship = (Ship*)_following;
	Vector3 _origen = ship->model->getPosition();
	this->offset = _offset;
	this->alive = true;
	this->origen = _origen;
	Vector3 porigen, velocidad, back;
	unsigned int birth,ttl,now;
	float x,y,z,rango,mod_vel,uni,randm;
	rango = 1.0f;
	now = getTime();
	srand(now);
	data.resize(_number);
	color = ship->shipColor;
	back = -ship->model->frontVector();
	size = _size;
	size_max = _size;
	for (int i = 0; i < _number; i++ )
	{
		randm = rand();
		x = ((randm / RAND_MAX)-0.5) * rango / 10.0;
		randm = rand();
		y = ((randm / RAND_MAX)-0.5) * rango / 10.0;
		randm = rand();
		z = ((randm / RAND_MAX)-0.5) * rango / 10.0;
		porigen = _origen + Vector3(x,y,z);

		randm = rand();
		x = ((randm / RAND_MAX)-0.5) * (rango/1) ;
		randm = rand();
		y = ((randm / RAND_MAX)-0.5) * (rango/1) ;
		randm = rand();
		z = origen.z;// ((randm / RAND_MAX)-0.5) * (rango/1000) ;
		
		//velocidad = back - Vector3(x,y,z);
		//velocidad.normalize();
		//velocidad = velocidad * 0;
		velocidad.set(0,0,0);
		randm = rand();
		x = ((randm / RAND_MAX)-0.5) * 300.0 ;
		ttl = 300.0 + x;
		data[i] = (new Particle(porigen, velocidad, now, ttl, Vector2(size,1)));
	}
}

void enginePS::recalc(){

	if (!this->alive) return;
	if (following == NULL) return;
	Ship* ship = (Ship*)following;
	this->alive = ship->alive;
	Vector3 pos = ship->model->getPosition();
	origen = *following->model * offset;
	
	unsigned long now = getTime();
	double elapsed;
	float ratio;
	size = size_max * ship->speed;
	
	for(int i = 0; i < data.size(); i++)
	{
		elapsed = now - data[i]->birth;
		if (elapsed == 0) elapsed ++;
		ratio = 1.0 - ((float)elapsed/(float)data[i]->ttl);
		if (elapsed < data[i]->ttl){
			data[i]->size.x = size;
			data[i]->posicion = data[i]->origen + data[i]->velocidad * elapsed;
			
		}
	}
	//hay regeneracion
	for(int i = 0; i < data.size(); i++)
	{
		elapsed = now - data[i]->birth;
		if( elapsed >= data[i]->ttl){
			data[i]->origen = origen;
			data[i]->birth = now;
			data[i]->size = Vector2(size,1);
		}
	}
}

void enginePS::render(){
	if (!this->alive){
		return;
	}
	if (this->following == NULL){

		return;
	}
	//Hay que hacer bill boarding
	glPushAttrib(GL_ALL_ATTRIB_BITS);
	glDepthMask(false);
	glEnable(GL_BLEND);
	glBlendFunc(GL_SRC_ALPHA, GL_ONE);
	glEnable(GL_TEXTURE_2D);
	glDisable(GL_CULL_FACE);
	Scene::getScene()->ActivateTexture("gauss_noise");
	
	glColor4f(color.x,color.y,color.z,1.0);
	glBegin(GL_QUADS);
	
	for (int i = 0; i < data.size(); i++)
	{
		data[i]->render();
	}
	glEnd();
	glDisable(GL_TEXTURE_2D);
	GLenum errCode ;
	const GLubyte *errString;
	if ((errCode = glGetError()) != GL_NO_ERROR) {
		errString = gluErrorString(errCode);
		fprintf (stderr, "OpenGL Error: %s\n", errString);
	}
	
	//en Debug da error el assert...

	//assert(errCode == GL_NO_ERROR);
	/*
	glPointSize(5);
	glBegin(GL_POINTS);
	for (int i = 0; i < data.size(); i++)
	{
		glVertex3fv(data[i]->origen.v);
	}
	glEnd();
	*/
	glPopAttrib();
}